home *** CD-ROM | disk | FTP | other *** search
/ HAM Radio 3.2 / Ham Radio Version 3.2 (Chestnut CD-ROMs)(1993).ISO / packet / n17jsrc / timer.c < prev    next >
C/C++ Source or Header  |  1991-10-19  |  6KB  |  263 lines

  1. /* General purpose software timer facilities
  2.  * Copyright 1991 Phil Karn, KA9Q
  3.  */
  4. #include <stdio.h>
  5. #include "global.h"
  6. #include "timer.h"
  7. #include "proc.h"
  8. #include "mbuf.h"
  9. #include "commands.h"
  10. #include "daemon.h"
  11. #include "hardware.h"
  12. #include "socket.h"
  13.  
  14. /* Head of running timer chain.
  15.  * The list of running timers is sorted in increasing order of expiration;
  16.  * i.e., the first timer to expire is always at the head of the list.
  17.  */
  18. static struct timer *Timers;
  19.  
  20. static void t_alarm __ARGS((void *x));
  21.  
  22. /* Process that handles clock ticks */
  23. void
  24. timerproc(i,v1,v2)
  25. int i;
  26. void *v1,*v2;
  27. {
  28.     register struct timer *t, *p;
  29.     register struct timer *expired;
  30.     char i_state;
  31.     void (**vf)();
  32.  
  33.     for(;;){
  34.         i_state = dirps();    /* Tick is modified by an interrupt */
  35.         while(Tick == 0)
  36.             pwait(&Tick);
  37.         Tick = 0;
  38.         restore(i_state);
  39.  
  40.         if(!istate()){
  41.             restore(1);
  42.             printf("timer: ints were off!\n");
  43.             fflush(stdout);        /* make sure it gets out */
  44.         }
  45.  
  46.         /* Call the functions listed in config.c */
  47.         for(vf = Cfunc;*vf != NULL;vf++)
  48.             (*vf)();
  49.  
  50.         tflush();    /* Flush current session output */
  51.         pwait(NULL);    /* Let them all do their writes */
  52.         rflush();    /* Flush out buffered console stuff */
  53.         fflush(stdout);    /* And flush out stdout too */
  54.  
  55.         if(Timers == NULLTIMER)
  56.             continue;    /* No active timers, all done */
  57.  
  58.         /* Initialize null expired timer list */
  59.         expired = NULLTIMER;
  60.  
  61.         /* Move expired timers to expired list. Note use of
  62.          * subtraction and comparison to zero rather than the
  63.          * more obvious simple comparison; this avoids
  64.          * problems when the clock count wraps around.
  65.          */
  66.         while(Timers != NULLTIMER && (Clock - Timers->expiration) >= 0){
  67.             if(Timers->next == Timers){
  68.                 printf("PANIC: Timer loop at %lx\n",
  69.                  (long)Timers);
  70.                 iostop();
  71.                 exit(1);
  72.             }
  73.             /* Save Timers since stop_timer will change it */
  74.             t = Timers;
  75.             stop_timer(t);
  76.             /* Add to expired timer list */
  77.             if(expired == NULLTIMER){
  78.                 expired = t;
  79.             } else {
  80.                 for(p = expired ; p->next != NULLTIMER ; p = p->next);
  81.                 p->next = t;    /* place at end of chain */
  82.             }
  83.             t->next = NULLTIMER;
  84.         }
  85.         /* Now go through the list of expired timers, removing each
  86.          * one and kicking the notify function, if there is one
  87.          * Note that the state should ne TIMER_STOP. We just stopped
  88.          * it remember? Now is someone else changed it, ignore timer.
  89.          */
  90.         while((t = expired) != NULLTIMER){
  91.             expired = t->next;
  92.             if(t->state == TIMER_STOP){
  93.                 t->state = TIMER_EXPIRE;
  94.                 if(t->func)
  95.                     (*t->func)(t->arg);
  96.             }
  97.         }
  98.         pwait(NULL);    /* Let them run before handling more ticks */
  99.     }
  100. }
  101. /* Start a timer */
  102. void
  103. start_timer(t)
  104. struct timer *t;
  105. {
  106.     register struct timer *tnext;
  107.     struct timer *tprev = NULLTIMER;
  108.  
  109.     if(t == NULLTIMER)
  110.         return;
  111.     if(t->state == TIMER_RUN)
  112.         stop_timer(t);
  113.     if(t->duration == 0)
  114.         return;        /* A duration value of 0 disables the timer */
  115.  
  116.     t->expiration = Clock + t->duration;
  117.     t->state = TIMER_RUN;
  118.  
  119.     /* Find right place on list for this guy. Once again, note use
  120.      * of subtraction and comparison with zero rather than direct
  121.      * comparison of expiration times.
  122.      */
  123.     for(tnext = Timers;tnext != NULLTIMER;tprev=tnext,tnext = tnext->next){
  124.         if((tnext->expiration - t->expiration) >= 0)
  125.             break;
  126.     }
  127.     /* At this point, tprev points to the entry that should go right
  128.      * before us, and tnext points to the entry just after us. Either or
  129.      * both may be null.
  130.      */
  131.     if(tprev == NULLTIMER)
  132.         Timers = t;        /* Put at beginning */
  133.     else
  134.         tprev->next = t;
  135.  
  136.     t->next = tnext;
  137. }
  138. /* Stop a timer */
  139. void
  140. stop_timer(timer)
  141. struct timer *timer;
  142. {
  143.     register struct timer *t;
  144.     struct timer *tlast = NULLTIMER;
  145.  
  146.     if(timer == NULLTIMER || timer->state != TIMER_RUN)
  147.         return;
  148.  
  149.     /* Verify that timer is really on list */
  150.     for(t = Timers;t != NULLTIMER;tlast = t,t = t->next)
  151.         if(t == timer)
  152.             break;
  153.  
  154.     if(t == NULLTIMER)
  155.         return;        /* Should probably panic here */
  156.  
  157.     /* Delete from active timer list */
  158.     if(tlast != NULLTIMER)
  159.         tlast->next = t->next;
  160.     else
  161.         Timers = t->next;    /* Was first on list */
  162.  
  163.     t->state = TIMER_STOP;
  164. }
  165. /* Return milliseconds remaining on this timer */
  166. int32
  167. read_timer(t)
  168. struct timer *t;
  169. {
  170.     int32 remaining;
  171.  
  172.     if(t == NULLTIMER || t->state != TIMER_RUN)
  173.         return 0;
  174.     remaining = t->expiration - Clock;
  175.     if(remaining <= 0)
  176.         return 0;    /* Already expired */
  177.     else
  178.         return remaining * MSPTICK;
  179. }
  180. void
  181. set_timer(t,interval)
  182. struct timer *t;
  183. int32 interval;
  184. {
  185.     if(t == NULLTIMER)
  186.         return;
  187.     /* Round up small nonzero intervals to one tick */
  188.     if(0 < interval && interval <= MSPTICK)
  189.         t->duration = 1;
  190.     else
  191.         t->duration = interval/MSPTICK;
  192. }
  193. /* Delay process for specified number of milliseconds.
  194.  * Normally returns 0; returns -1 if aborted by alarm.
  195.  */
  196. int
  197. pause(ms)
  198. int32 ms;
  199. {
  200.     int val;
  201.  
  202.     if(Curproc == NULLPROC || ms == 0)
  203.         return 0;
  204.     alarm(ms);
  205.     /* The actual event doesn't matter, since we'll be alerted */
  206.     while(Curproc->alarm.state == TIMER_RUN){
  207.         if((val = pwait(Curproc)) != 0)
  208.             break;
  209.     }
  210.     alarm(0L); /* Make sure it's stopped, in case we were killed */    
  211.     return (val == EALARM) ? 0 : -1;
  212. }
  213. static void
  214. t_alarm(x)
  215. void *x;
  216. {
  217.     alert((struct proc *)x,EALARM);
  218. }
  219. /* Send signal to current process after specified number of milliseconds */
  220. void
  221. alarm(ms)
  222. int32 ms;
  223. {
  224.     if(Curproc != NULLPROC){
  225.         set_timer(&Curproc->alarm,ms);
  226.         Curproc->alarm.func = t_alarm;
  227.         Curproc->alarm.arg = (char *)Curproc;
  228.         start_timer(&Curproc->alarm);
  229.     }
  230. }
  231. /* Convert time count in seconds to printable days:hr:min:sec format */
  232. char *
  233. tformat(t)
  234. int32 t;
  235. {
  236.     static char buf[17],*cp;
  237.     unsigned int days,hrs,mins,secs;
  238.     int minus;
  239.  
  240.     if(t < 0){
  241.         t = -t;
  242.         minus = 1;
  243.     } else
  244.         minus = 0;
  245.  
  246.     secs = t % 60;
  247.     t /= 60;
  248.     mins = t % 60;
  249.     t /= 60;
  250.     hrs = t % 24;
  251.     t /= 24;
  252.     days = t;
  253.     if(minus){
  254.         cp = buf+1;
  255.         buf[0] = '-';
  256.     } else
  257.         cp = buf;
  258.     sprintf(cp,"%u:%02u:%02u:%02u",days,hrs,mins,secs);
  259.     
  260.     return buf;
  261. }
  262.     
  263.